package top.lshaci.learning.activiti.util;

import cn.hutool.core.util.StrUtil;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * ProcessEngineSingleton
 *
 * @author lshaci
 * @since 1.0.0
 */
public enum ProcessEngineSingleton {

    /**
     * 流程引擎单例
     */
    singleton;

    /**
     * 流程引擎
     */
    private final ProcessEngine processEngine;

    ProcessEngineSingleton() {
        this.processEngine = ProcessEngines.getDefaultProcessEngine();
    }

    /**
     * 流程引擎
     * 工作流的核心。用于获取相应的服务
     *
     * @return 流程引擎
     */
    public ProcessEngine processEngine() {
        return this.processEngine;
    }

    /**
     * 仓库服务：管理流程定义（规则）
     *
     * @return 仓库服务
     */
    public RepositoryService repositoryService() {
        return this.processEngine.getRepositoryService();
    }

    /**
     * 运行时服务：执行管理，包括启动、推进、删除流程实例等操作
     *
     * @return 运行时服务
     */
    public RuntimeService runtimeService() {
        return this.processEngine.getRuntimeService();
    }

    /**
     * 历史服务：历史管理（执行完数据的管理）
     *
     * @return 历史服务
     */
    public HistoryService historyService() {
        return this.processEngine.getHistoryService();
    }

    /**
     * 任务服务：任务管理
     *
     * @return 任务服务
     */
    public TaskService taskService() {
        return this.processEngine.getTaskService();
    }

    /**
     * 身份服务：组织机构管理
     *
     * @return 身份服务
     */
    public IdentityService identityService() {
        return this.processEngine.getIdentityService();
    }

    /**
     * 表单服务：一个可选服务，任务表单管理
     *
     * @return 表单服务
     */
    public FormService formService() {
        return this.processEngine.getFormService();
    }

    /**
     * 任务调度服务
     *
     * @return 任务调度服务
     */
    public ManagementService managementService() {
        return this.processEngine.getManagementService();
    }

    /**
     * 部署流程
     *
     * @param resourceName classpath 下的bmpn文件和png文件名称
     * @return 部署信息
     */
    public Deployment deploy(String resourceName) {
        return repositoryService()
                .createDeployment()
                .name(resourceName + "部署")
                .addClasspathResource(resourceName + ".bpmn")
                .addClasspathResource(resourceName + ".png")
                .deploy();
    }

    /**
     * 开始流程
     *
     * @param processDefinitionKey 流程定义KEY
     * @return 流程实例
     */
    public ProcessInstance start(String processDefinitionKey) {
        return runtimeService().startProcessInstanceByKey(processDefinitionKey);
    }

    /**
     * 查询私有任务
     *
     * @param assignee 办理人
     * @return 任务信息
     */
    public List<Task> personalTask(String assignee) {
        return taskService().createTaskQuery()
                .taskAssignee(assignee)
                .list();
    }

    /**
     * 获取任务节点的出口
     *
     * @param taskId 任务ID
     * @return 任务节点的出口
     */
    public List<String> getOutGoingTransNames(String taskId) {
        // 1.获取任务
        Task task = taskService().createTaskQuery().taskId(taskId).singleResult();
        // 2.获取流程定义
        ProcessDefinition processDefinition = repositoryService().getProcessDefinition(task.getProcessDefinitionId());
        // 3.获取流程模型
        BpmnModel bpmnModel = repositoryService().getBpmnModel(processDefinition.getId());
        // 4.获取所有的连线
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(task.getTaskDefinitionKey());
        // 5.提取所有出口的名称，封装成集合
        List<SequenceFlow> outgoingFlows = flowNode.getOutgoingFlows();
        List<String> transNames = outgoingFlows.stream()
                .filter(Objects::nonNull)
                .map(SequenceFlow::getName)
                .filter(StrUtil::isNotBlank)
                .sorted((a, b) -> "同意".equals(a) ? -1 : a.compareTo(b))
                .collect(Collectors.toList());

        if (transNames.size() == 0) {
            transNames.add("提交");
        }
        return transNames;
    }
}
